Process.Instructions .parser :-
	repeat, -- Use fail loops to minimize stack usage
	Process.Instruction .parser,
	scan.EOF (parser.scanner .parser ^) #

Process.Instruction .parser :-
	once (
		Parse.Instruction .parser .tree0;
		raise "Internal parser error"
	), (
		.tree0 = $; -- Pseudo instructions, labels or something really nothing
		once (
			Check.Instruction .tree0 .size;
			raise "Internal checker error"
		),
		once (
			Simplify.OpTree .tree0 .tree1;
			raise "Internal simplifier error"
		),
		if (get HEXDUMP yes, get PASS 2) then (
			nl, ascii .r 13, ascii .t 9,
			Emit.GetAddress .addr, Hex4 .addr .hex, write .hex .t,
			Dump.Instruction .tree1 .str,
			concat .str .r .t .t .t .t .t .w, write .w
		),
		once (
			Generate.Instruction .tree1 .size .parts;
			Error "Invalid operand pattern"
		),
		once (
			not Config.Mode AMD64, .parts1 = .parts;
			Set.REX .parts .size .parts1;
			raise "Internal AMD64 REX prefix calculation error"
		),
		once (
			Emit.Parts .parts1;
			raise "Internal emitter error"
		)
	) ! #

Parse.Instruction .parser .tree :-
	scan.match (parser.scanner .parser ^) (ID .inst) !
	Parse.StartWith .parser .inst .tree #
Parse.Instruction .parser $ :-
	scan.match (parser.scanner .parser ^) .token, -- Eats up the rubbish
	nth .token 1 .t,
	concat "Unknown instruction " .t .str,
	Error .str #

Parse.StartWith . .inst (LABEL .label) :-
	char.at .inst -1 ".", -- It could well be a label
	substr .inst 0 -1 .label #
Parse.StartWith .parser .inst .tree :-
	Parse.Operands .parser .inst .tree #


-- Parsing Instructions --

Parse.Operands . .inst (.inst) :-
	Instruction.NoOp .inst . ! #
Parse.Operands .parser .inst (.inst .op) :-
--	Instruction.AccOp .inst .;
	Instruction.RegOp .inst .;
	Instruction.ImmOp .inst .;
	Instruction.RmOp .inst . .;
	Instruction.NearJumpOp .inst .;
	Instruction.BranchOp .inst .;
	Instruction.Data .inst . !
	Parse.Operand .parser .op;
	Error "Bad syntax" #
Parse.Operands .parser .inst (.inst .op1 .op2) :-
	Instruction.AccImmOp .inst .;
	Instruction.RmImmOp .inst . .;
	Instruction.RmRegOp .inst .;
	Instruction.TwoOps .inst !
	Parse.Operand .parser .op1,
	scan.match (parser.scanner .parser ^) (SYM ","),
	Parse.Operand .parser .op2;
	Error "Bad syntax" #
Parse.Operands . . . :- Error "Unknown instruction" #


-- Generating Instructions --

	-- Generate output:
	-- ([Legacy Prefix] [REX Prefix] [Opcode] [Opcode Reg]
	--   [Mod] [r] [RM] [S] [I] [B] [Displacement] [Immediate])

	-- Special instructions: labels, data definitions
Generate.Instruction (LABEL .label) . $ :-
	Label.Define .label ! #
Generate.Instruction (.dd (IMM .value)) .size $ :-
	Instruction.Data .dd .size,
	Emit.Immediate .size .value ! #

	-- No operand instructions
Generate.Instruction .inst . ($ $ .cc $ $ $ $ $ $ $ $ $) :-
	Instruction.NoOp .inst .cc ! #

	-- Single operand instructions
Generate.Instruction (.inst (IMM .value)) .size
	($ $ .cc $ $ $ $ $ $ $ $ (I .size .value)) :-
	Instruction.ImmOp .inst .cc, Config.WordSize .size ! #

Generate.Instruction (.inst (GR .size .r)) .size
	($ $ .cc .r $ $ $ $ $ $ $ $) :-
	Instruction.RegOp .inst .cc, Config.WordSize .size ! #

Generate.Instruction (.inst .op) .size
	($ $ .cc1 $ .mod .d .RM .S .I .B .disp $) :-
	Instruction.RmOp .inst .cc .d !
	Adjust.IfByte .inst .size .cc .cc1,
	ModRM.Calc .op (.mod .RM .S .I .B .disp) #

Generate.Instruction (.inst (IMM .address)) .size
	($ $ .cc $ $ $ $ $ $ $ $ (I .size .offset)) :-
	Instruction.NearJumpOp .inst .cc !
	Emit.GetAddress .current,
	Emit.Length .cc .ccLen, Config.NearAddressSize .size,
	let .offset (.address - .current - .ccLen - .size) #

Generate.Instruction (.inst (IMM .address)) .size
	($ $ .cc $ $ $ $ $ $ $ $ (I .size .offset)) :-
	Instruction.BranchOp .inst .tttn !
	Emit.GetAddress .current,
	Config.NearAddressSize .size,
	let .offset (.address - .current - 2 - .size),
	Emit.AddBits ('0F', +'80') .tttn .cc #

	-- Two operands instructions
Generate.Instruction (.inst .op (IMM .i)) .size
	($ $ .cc1 $ .mod .d .RM .S .I .B .disp (I .size .i)) :-
	Instruction.RmImmOp .inst .cc .d !
	Adjust.IfByte .inst .size .cc .cc1,
	ModRM.Calc .op (.mod .RM .S .I .B .disp) #

Generate.Instruction (.inst .op1 (GR .size .r)) .size
	($ $ .cc1 $ .mod .r .RM .S .I .B .disp $) :-
	Instruction.RmRegOp .inst .cc !
	Adjust.IfByte .inst .size .cc .cc1 !
	ModRM.Calc .op1 (.mod .RM .S .I .B .disp) #

Generate.Instruction (.inst (GR .size .r) .op2) .size
	($ $ .cc1 $ .mod .r .RM .S .I .B .disp $) :-
	Instruction.RmRegOp .inst .cc !
	Adjust.RevOpIfByte .inst .size .cc .cc1 !
	ModRM.Calc .op2 (.mod .RM .S .I .B .disp) #


-- REX Prefix for AMD64 --

Set.REX $ . $ #
Set.REX (.prefix $ .opcode .opReg .mod .r .RM .S .I .B .disp .imm) .size
	(.prefix .REX3 .opcode .opReg2 .mod .r2 .RM2 .S .I1 .B1 .disp .imm) :-
	REX.Requirement .opReg .opReg1 .req1,
	REX.Requirement .r .r1 .req2,
	REX.Requirement .RM .RM1 .req3,
	Calc.REX ($ .opReg1 .r1 .RM1 .I .B) .size
		(.REX0 .opReg2 .r2 .RM2 .I1 .B1) !
	REX.CheckReq .req1 .REX0 .REX1,
	REX.CheckReq .req2 .REX1 .REX2,
	REX.CheckReq .req3 .REX2 .REX3 #

	-- To gather and check REX exist/unexist condition for special registers
REX.Requirement (.req .r) .r (.req) :- ! #
REX.Requirement .reg .reg $ # -- No requirements

REX.CheckReq $ .REX .REX # -- No requirement
REX.CheckReq NOREX $ $ #
REX.CheckReq REX $ 64 :- ! # -- Enforces a "useless" REX 40h
REX.CheckReq REX . 40 #
REX.CheckReq . . . :- Error "REX byte conflict" #

	-- Retrieves bit-3 in operands and generate REX prefix. Refer AMD manual
Calc.REX ($ .opReg .r .RM .I .B) .size (.REX .opReg1 .r1 .RM1 .I1 .B1) :-
	ExtractBit3 .size 8 . .REX.W, -- 64-bit operation?
	ExtractBit3 .r 4 .r1 .REX.R, -- ModRM reg bit extension
	ExtractBit3 .I 2 .I1 .REX.X, -- SIB index bit extension
	if (.RM >= 8) then ( -- ModRM r/m, SIB base or opcode reg bit extension
		.REX.B = 1, let .RM1 (.RM - 8)
	) else (.RM1 = .RM,
		if (.B >= 8) then (
			.REX.B = 1, let .B1 (.B - 8)
		) else (.B1 = .B,
			if (.opReg >= 8) then (
				.REX.B = 1, let .opReg1 (.opReg - 8)
			) else (
				.REX.B = 0, .opReg1 = .opReg
			)
		)
	),
	let .REX (64 + .REX.W + .REX.R + .REX.X + .REX.B),
	not (.REX = 64) # -- REX prefix is actually not needed, skip it
Calc.REX .parts . .parts # -- No need REX prefix

ExtractBit3 .n .ifBit3 (.n1) (.flag) :-
	if (bound .n, .n >= 8) then (
		.flag = .ifBit3, let .n1 (.n and 7)
	) else (
		.flag = 0, .n1 = .n
	) #


-- Labels --

Label.Define .label :-
	get PASS 1,
	Emit.GetAddress .address,
	inserta (LABEL .label .address) ! #
Label.Define .label :-
	get PASS 2,
	Emit.GetAddress .address,
	Label.Get .label .address;
	Error.PassTwo "Label address differed between passes" ! #

Label.Get .label .address :-
	search (LABEL .label .address) ! #
Label.Get . .address :-
	get PASS 1, .address = 0 ! # -- To cope with forward-defined labels
Label.Get . . :-
	Error.PassTwo "Undefined label" #


-- Correctness Checkings --

Check.Instruction (.inst .op1) (.size) :-
	Check.OperandSize .op1 .size, (
		Instruction.BranchOp .inst .;
		Instruction.NearJumpOp .inst .;
		Instruction.Data .inst .size;
		Instruction.WordSizeOps .inst, Config.WordSize .size;
		Check.KnowSize .size
	) #
Check.Instruction (.inst .op1 .op2) (.size1) :-
	Check.OperandSize .op1 .size1,
	Check.OperandSize .op2 .size2, (
		Instruction.DiffSizeOps .inst;
		.size1 = .size2;
		Error "Operands in different sizes"
	) !
	Check.KnowSize .size1,
	Check.KnowSize .size2 #
Check.Instruction . . #

Check.KnowSize .size :-
	bound .size; Error "Operand size unknown" ! #


-- General Emission Rules --

Adjust.RevOpIfByte .inst .size .cc .cc2 :- -- Operands are reversed, i.e. reg, r/m
	Emit.AddBits .cc 2 .cc1,
	Adjust.IfByte .inst .size .cc1 .cc2 #

Adjust.IfByte .inst . .cc .cc :- -- No addition for word size-only instructions
	Instruction.WordSizeOps .inst ! #
Adjust.IfByte . .size .cc .cc1 :-
	if (.size = 1) then (
		.cc1 = .cc
	) else (
		Emit.AddBits .cc 1 .cc1
	) #


-- Mod/RM & SIB Byte Formation --

	-- Returns (Mod R/M S I B [Disp]) #
	-- Just why this encoding is so ugly?
ModRM.Calc (GR . .r) (3 .r $ $ $ $) #
ModRM.Calc (MEM $ $ . .disp) (0 5 $ $ $ (I .size .disp)) :-
	Config.PointerSize .size #
ModRM.Calc (MEM $ (GR .size .index) .scale .disp)
	(0 4 .SI .index 5 (I .size .disp)) :-
	Config.PointerSize .size, Scale.Index .scale .SI #
ModRM.Calc (MEM (GR .size 4) $ . 0) (0 4 0 4 4 $) :-
	Config.PointerSize .size # -- [ESP] requires a SIB byte
ModRM.Calc (MEM (GR .size .base) $ . 0) (0 .base $ $ $ $) :-
	Config.PointerSize .size, not (.base = 5) # -- [EBP] be encoded as [EBP+0]
ModRM.Calc (MEM (GR .size 4) $ . .disp) (2 4 0 4 4 (I .size .disp)) :-
	Config.PointerSize .size #
ModRM.Calc (MEM (GR .size .base) $ . .disp) (4 .base $ $ $ (I .size .disp)) :-
	Config.PointerSize .size #
ModRM.Calc (MEM (GR .size .base) (GR .size .index) .scale 0)
	(0 4 .SI .index .base $) :-
	Config.PointerSize .size, not (.base = 4), Scale.Index .scale .SI #
ModRM.Calc (MEM (GR .size .base) (GR .size .index) .scale .disp)
	(2 4 .SI .index .base (I .size .disp)) :-
	Config.PointerSize .size, Scale.Index .scale .SI #
ModRM.Calc . . :- Error "Bad memory expression" #
